#ifndef ARC_LFU_PART_HPP
#define ARC_LFU_PART_HPP

// #include <unordered_map>
#include <list>
#include <map>
#include <mutex>

#include "./ArcNode.hpp"

namespace CachePool
{
    template <typename Key, typename Value>
    class ArcLfuPart
    {
    public:
        using NodeType = ArcNode<Key, Value>;
        using NodePtr = std::shared_ptr<NodeType>;
        using NodeMap = std::unordered_map<Key, NodePtr>;
        using FreqMap = std::map<size_t, std::list<NodePtr>>; // 这里相比LFU换了一种方式

        ArcLfuPart(const size_t capacity, const size_t transformThreshold)
            : capacity_(capacity), ghostCapacity_(capacity), transformThreshold_(transformThreshold), minFreq_(0)
        {
            this->initNodeLists();
        }

        bool set(const Key &key, const Value &value)
        {
            if (this->capacity_ <= 0)
            {
                return false;
            }

            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->mainNodeMap_.find(key);
            if (it == this->mainNodeMap_.end())
            {
                return this->addMainNode(key, value);
            }

            return this->modMainNode(it->second, value);
        }

        bool get(const Key &key, Value &value)
        {
            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->mainNodeMap_.find(key);
            if (it == this->mainNodeMap_.end())
            {
                return false;
            }

            value = it->second->getValue();
            this->moveMainMfuNode(it->second);
            return true;
        }

        bool checkGhost(const Key &key)
        {
            auto it = this->ghostNodeMap_.find(key);
            if (it == this->ghostNodeMap_.end())
            {
                return false;
            }

            this->delListNode(it->second);
            this->ghostNodeMap_.erase(it);
            return true;
        }

        // 没有变动淘汰队列容量
        void increaseCapacity()
        {
            ++this->capacity_;
        }

        bool decreaseCapacity()
        {
            if (this->capacity_ <= 0)
            {
                return false;
            }

            if (this->mainNodeMap_.size() == this->capacity_)
            {
                this->evictMainLfuNode();
            }
            --this->capacity_;
            return true;
        }

    private:
        void initNodeLists()
        {
            this->ghostDummyHead_ = std::make_shared<NodeType>();
            this->ghostDummyTail_ = std::make_shared<NodeType>();
            this->ghostDummyHead_->next_ = this->ghostDummyTail_;
            this->ghostDummyTail_->prev_ = this->ghostDummyHead_;
        }

        bool addMainNode(const Key &key, const Value &value)
        {
            if (this->mainNodeMap_.size() >= this->capacity_)
            {
                this->evictMainLfuNode();
            }

            NodePtr newNode = std::make_shared<NodeType>(key, value);
            this->mainNodeMap_[key] = newNode;

            // 将新节点添加到频率为1的列表中
            if (this->freqMap_.find(1) == this->freqMap_.end())
            {
                this->freqMap_[1] = std::list<NodePtr>{};
            }
            this->freqMap_[1].emplace_back(newNode);

            this->minFreq_ = 1;

            return true;
        }

        void evictMainLfuNode()
        {
            if (this->freqMap_.empty())
            {
                return;
            }

            // 获取最小频率的列表
            auto &minFreqList = this->freqMap_[this->minFreq_]; // 注意引用
            if (minFreqList.empty())
            {
                return;
            }

            // 移除最少使用的节点
            NodePtr lfuNode = minFreqList.front();
            minFreqList.pop_front();

            // 如果该频率的列表为空，则删除该频率项
            if (minFreqList.empty())
            {
                this->freqMap_.erase(this->minFreq_);

                // 更新最小频率
                if (!this->freqMap_.empty())
                {
                    this->minFreq_ = this->freqMap_.begin()->first; // map是红黑树有序的，取第一个最小
                }
            }

            // 从主缓存中移除
            this->mainNodeMap_.erase(lfuNode->getKey());

            // 将节点移到幽灵缓存
            if (this->ghostNodeMap_.size() >= this->ghostCapacity_)
            {
                this->evictGhostOldestNode();
            }
            this->addGhostNode(lfuNode);
        }

        void evictGhostOldestNode()
        {
            NodePtr oldestNode = this->ghostDummyHead_->next_;
            if (oldestNode == this->ghostDummyTail_)
            {
                return;
            }

            this->delListNode(oldestNode);
            this->ghostNodeMap_.erase(oldestNode->getKey());
        }

        void delListNode(NodePtr node)
        {
            node->prev_->next_ = node->next_;
            node->next_->prev_ = node->prev_;
        }

        void addGhostNode(NodePtr node)
        {
            this->addGhostListNode(node);
            this->ghostNodeMap_[node->getKey()] = node;
        }

        void addGhostListNode(NodePtr node)
        {
            node->prev_ = this->ghostDummyTail_->prev_;
            node->next_ = this->ghostDummyTail_;

            this->ghostDummyTail_->prev_->next_ = node; // 这里不能改顺序
            this->ghostDummyTail_->prev_ = node;
        }

        bool modMainNode(NodePtr node, const Value &value)
        {
            node->setValue(value);
            this->moveMainMfuNode(node);
            return true;
        }

        void moveMainMfuNode(NodePtr node)
        {
            size_t oldFreq = node->getAccessCount();
            node->incrementAccessCount();
            size_t newFreq = node->getAccessCount();

            // 从旧频率列表中移除
            auto &oldList = this->freqMap_[oldFreq];
            oldList.remove(node);

            if (oldList.empty())
            {
                this->freqMap_.erase(oldFreq);
                if (oldFreq == this->minFreq_)
                {
                    this->minFreq_ = newFreq;
                }
            }

            // 添加到新频率列表
            if (this->freqMap_.find(newFreq) == this->freqMap_.end())
            {
                this->freqMap_[newFreq] = std::list<NodePtr>{};
            }
            this->freqMap_[newFreq].emplace_back(node);
        }

    private:
        size_t capacity_;
        size_t ghostCapacity_;
        size_t transformThreshold_;
        size_t minFreq_;

        NodePtr ghostDummyHead_;
        NodePtr ghostDummyTail_;

        FreqMap freqMap_;

        NodeMap mainNodeMap_;
        NodeMap ghostNodeMap_;

        std::mutex mutex_;
    };
} // namespace CachePool

#endif // ARC_LFU_PART_HPP